package com.mail.anteater.hibernate;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.DetachedCriteria;

public class HibernateUtil {

	protected static Session session = null;
	final static Logger logger = Logger.getLogger(HibernateUtil.class);

	public static boolean delete(Object obj, boolean isNestedOperation) {

		boolean result = false;
		Transaction tx = null;

		try {
			session = SessionFactoryUtil.getCurrentSession();
			tx = session.beginTransaction();
			session.delete(obj);
			if(!isNestedOperation){
				tx.commit();	
			}
			result = true;
		} catch (Exception e) {
			logger.error("delete() - exception: ", e);
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
					logger.error("delete() - Transaction rolled back : " + obj.getClass().toString(), e);
				} catch (HibernateException e1) {
					logger.error("delete() - Error rolling back transaction : " + obj.getClass().toString(), e1);
				}
			}
		} finally {
			if(!isNestedOperation){
				SessionFactoryUtil.endTransaction();	
			}
		}
		return result;
	}

	public static boolean create(Object obj, boolean isNestedOperation) {
		Transaction tx = null;
		boolean result = false;
		try {
			session = SessionFactoryUtil.getCurrentSession();
			tx = session.beginTransaction();
			session.save(obj);
			if(!isNestedOperation){
				tx.commit();	
			}
			result = true;
		} catch (Exception e) {
			logger.error("create() - exception: ", e);
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
					logger.error("create() - Transaction rolled back : " + obj.getClass().toString(), e);
				} catch (HibernateException e1) {
					logger.error("create() - Error rolling back transaction", e1);
				}
			}
		} finally {
			if(!isNestedOperation){
				SessionFactoryUtil.endTransaction();	
			}
		}
		return result;
	}

	/*public static boolean callable(String procedureName, ArrayList<Parameter> params, boolean isNestedOperation) {
		Transaction tx = null;
		boolean result = false;
		try {
			session = SessionFactoryUtil.getCurrentSession();
			tx = session.beginTransaction();
			Query query = session.getNamedQuery(procedureName).setParameter(params.get(0).getName(), params.get(0).getValue());
			if(query == null) Func.println("null wor");
			for(Parameter p : params){
				query = query.setParameter(p.getName(), p.getValue());
			}
			query.executeUpdate();
			if(!isNestedOperation){
				if(tx != null){
					if(tx.isActive()){
						tx.commit();	
					}	
				}
			}	
			result = true;
		} catch (Exception e) {
			logger.error("callable() - Error executing procedure - " + procedureName + ", parameters - " + params.toString(), e);
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
					logger.error("callable() - Transaction rolled back : ", e);
				} catch (HibernateException e1) {
					logger.error("callable() - Error rolling back transaction", e1);
				}
			}
		} finally {
			if(!isNestedOperation){
				SessionFactoryUtil.endTransaction();	
			}	
		}
		return result;
	}*/
	
	@SuppressWarnings("unchecked")
	public static ArrayList<Object> customSelect(String query, boolean isNestedOperation) {
		Transaction tx = null;
		ArrayList<Object> items = new ArrayList<Object>();
		try {
			session = SessionFactoryUtil.getCurrentSession();
			tx = session.beginTransaction();
			Query hqlQuery = session.createQuery(query);
			List list = hqlQuery.list();
			if(list != null){
				if(list.size() > 0){
					items = (ArrayList<Object>)	list;
				}	
			}
			if(!isNestedOperation){
				tx.commit();	
			}
		} catch (Exception e) {
			logger.error("customSelect() - exception: ", e);
			items = null;
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
					logger.error("customQuery() - Transaction rolled back : " + query, e);
				} catch (HibernateException e1) {
					logger.error("customQuery() - Error rolling back transaction", e1);
				}
			}
		} finally {
			if(!isNestedOperation){
				SessionFactoryUtil.endTransaction();	
			}
		}
		return items;
	}
	
	public static boolean customQuery(String query, boolean isNestedOperation) {
		Transaction tx = null;
		boolean result = false;
		try {
			session = SessionFactoryUtil.getCurrentSession();
			tx = session.beginTransaction();
			Query hqlQuery = session.createQuery(query);
			hqlQuery.executeUpdate();
			if(!isNestedOperation){
				tx.commit();	
			}
			result = true;
		} catch (Exception e) {
			logger.error("customQuery() - exception: ", e);
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
					logger.error("customQuery() - Transaction rolled back : " + query, e);
				} catch (HibernateException e1) {
					logger.error("customQuery() - Error rolling back transaction", e1);
				}
			}
		} finally {
			if(!isNestedOperation){
				SessionFactoryUtil.endTransaction();	
			}
		}
		return result;
	}
	
	public static boolean update(Object obj, boolean isNestedOperation) {
		Transaction tx = null;
		boolean result = false;
		try {
			session = SessionFactoryUtil.getCurrentSession();

			tx = session.beginTransaction();			
			session.update(obj);
			if(!isNestedOperation){
				tx.commit();	
			}
			result = true;
		} catch (Exception e) {
			logger.error("update() - exception: ", e);
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
					logger.error("update() - Transaction rolled back : " + obj.getClass().toString(), e);
				} catch (HibernateException e1) {
					logger.error("update() - Error rolling back transaction > ", e1);
				}
			}
		} finally {
			if(!isNestedOperation){
				SessionFactoryUtil.endTransaction();	
			}
		}
		return result;
	}

	public static boolean createOrUpdate(Object obj, boolean isNestedOperation) {
		Transaction tx = null;
		boolean result = false;
		try {
			session = SessionFactoryUtil.getCurrentSession();

			tx = session.beginTransaction();			
			session.saveOrUpdate(obj);
			if(!isNestedOperation){
				tx.commit();	
			}
			result = true;
		} catch (Exception e) {
			logger.error("delete() - exception: ", e);
			if (tx != null && tx.isActive()) {
				try {
					// Second try catch as the rollback could fail as well
					tx.rollback();
					logger.error("createOrUpdate() - Transaction rolled back : " + obj.getClass().toString(), e);
				} catch (HibernateException e1) {
					logger.error("createOrUpdate() - Error rolling back transaction > ", e1);
				}
			}
		} finally {
			if(!isNestedOperation){
				SessionFactoryUtil.endTransaction();	
			}
		}
		return result;
	}
	
	public static ArrayList<Object> list(DetachedCriteria qry, boolean isNestedOperation) {
		return list(qry, 0, isNestedOperation);
	}

	public static ArrayList<Object> list(DetachedCriteria qry, int firstResult, boolean isNestedOperation) {
		return list(qry, firstResult, -1, isNestedOperation);
	}

	@SuppressWarnings("unchecked")
	public static ArrayList<Object> list(DetachedCriteria qry, int firstResult, int maxResult, boolean isNestedOperation) {
		Transaction tx = null;
/*		if (logger.isDebugEnabled()) {
			logger.debug("list: detachedCriteria=" + qry + ", firstResult=" + firstResult + ", maxResult=" + maxResult);
		}*/
		ArrayList<Object> items = new ArrayList<Object>();
		try {
			session = SessionFactoryUtil.getCurrentSession();
			tx = session.beginTransaction();
			Criteria criteria = qry.getExecutableCriteria(session);
			
			criteria.setFirstResult(firstResult);
			if (maxResult >= 0)
				criteria.setMaxResults(maxResult);
			List list = null;
			list = criteria.list();
			if(list.size() > 0){
				items = (ArrayList<Object>)	list;
			}		
			if(!isNestedOperation){
				tx.commit();	
			}
		} catch (HibernateException he) {
			items = null;
			logger.error("list: An error related with hibernate occured >", he);
		} catch (Exception e) {
			items = null;
			logger.error("list: A general error occured > ", e);
		} finally {
			if(!isNestedOperation){
				SessionFactoryUtil.endTransaction();	
			}			
		}
		
		return items;
	}
	
	@SuppressWarnings("unchecked")
	public static ArrayList<Object> list(DetachedCriteria qry, int firstResult, int maxResult, Transaction tx, Session session) {
/*		if (logger.isDebugEnabled()) {
			logger.debug("list: detachedCriteria=" + qry + ", firstResult=" + firstResult + ", maxResult=" + maxResult);
		}*/
		ArrayList<Object> items = new ArrayList<Object>();
		try {
			Criteria criteria = qry.getExecutableCriteria(session);
			criteria.setFirstResult(firstResult);
			if (maxResult >= 0)
				criteria.setMaxResults(maxResult);
			List list = null;
			list = criteria.list();
			if(list.size() > 0){
				items = (ArrayList<Object>)	list;
			}			 
		} catch (HibernateException he) {
			logger.error("list: An error related with hibernate occured > ", he);

		} catch (Exception e) {
			logger.error("list: A general error occured > ",  e);
		} 
		return items;
	}
}
